#include "app/local_tool.h"

using namespace std::chrono; 

namespace app {

int check_rect_in_img(cv::Rect& rect, cv::Mat& img) {
  if (rect.x < 0 || rect.y < 0) { return -1;}
  if (rect.width <= 0 || rect.height <= 0) { return -1;}
  if (rect.x + rect.width >= img.cols || rect.y + rect.height >= img.rows) { return -1;}
  return 0;
}

int struct_to_string(ConfigInfo& cfg_ifo, std::string& str, bool write_file) {
  Json::Value root;
  root["smartboxId"] = cfg_ifo.smartboxId;
  root["serialNumber"] = cfg_ifo.serialNumber;
  root["smartboxIp"] = cfg_ifo.smartboxIp;

  root["configVersion"] = cfg_ifo.configVersion;
  root["postAPI"]["uploadAlarmFast"] = cfg_ifo.postAPI.uploadAlarmFast;
  root["postAPI"]["uploadAlarmSlow"] = cfg_ifo.postAPI.uploadAlarmSlow;
  root["postAPI"]["checkDevice"] = cfg_ifo.postAPI.checkDevice;
  root["postAPI"]["uploadHttpHeart"] = cfg_ifo.postAPI.uploadHttpHeart;
  root["postAPI"]["queryDevice"] = cfg_ifo.postAPI.queryDevice;
  root["postAPI"]["uploadCameraImg"] = cfg_ifo.postAPI.uploadCameraImg;
  root["postAPI"]["uploadFile"] = cfg_ifo.postAPI.uploadFile;
  root["postAPI"]["imageDetect"] = cfg_ifo.postAPI.imageDetect;

  root["httpServer"] = cfg_ifo.httpServer;
  root["socketServer"] = cfg_ifo.socketServer;
  root["modelDir"] = cfg_ifo.modelDir;
  root["mediaDir"] = cfg_ifo.mediaDir;
  root["historyDir"] = cfg_ifo.historyDir;
  root["historyDay"] = cfg_ifo.historyDay;
  root["gps"] = cfg_ifo.gps;
  
  // mediaKitInfo
  root["mediaKitInfo"] = Json::Value(Json::objectValue);
  root["mediaKitInfo"]["mediaKitServer"] = cfg_ifo.mediaKitInfo.mediaKitServer;
  root["mediaKitInfo"]["mediaKitClient"] = cfg_ifo.mediaKitInfo.mediaKitClient;
  auto& mka = cfg_ifo.mediaKitInfo.mediaKitAPI;
  auto mediaKitAPI = Json::Value(Json::objectValue);
  mediaKitAPI["addCamera"] = mka.addCamera;
  mediaKitAPI["getVideo"] = mka.getVideo;
  mediaKitAPI["cameraProxy"] = mka.cameraProxy;
  mediaKitAPI["addDeleteStrategy"] = mka.addDeleteStrategy;
  root["mediaKitInfo"]["mediaKitAPI"] = mediaKitAPI;
  auto& ds = cfg_ifo.mediaKitInfo.deleteStrategy;
  auto deleteStrategy = Json::Value(Json::objectValue);
  deleteStrategy["mainStreamDay"] = ds.mainStreamDay;
  deleteStrategy["mainStreamHour"] = ds.mainStreamHour;
  deleteStrategy["subStreamDay"] = ds.subStreamDay;
  deleteStrategy["subStreamHour"] = ds.subStreamHour;
  root["mediaKitInfo"]["deleteStrategy"] = deleteStrategy;

  // tasks
  root["tasks"] = Json::Value(Json::arrayValue);
  for (auto t : cfg_ifo.tasks) { root["tasks"].append(t); }

  root["cameraGroups"] = Json::Value(Json::arrayValue);
  for (auto cg : cfg_ifo.cameraGroups) {
    Json::Value item;
    item["cameraInfo"]["rtspAddress"] = cg.cam_ifo.rtspAddress;
    item["cameraInfo"]["cameraIp"] = cg.cam_ifo.cameraIp;
    item["cameraInfo"]["cameraId"] = cg.cam_ifo.cameraId;
    item["cameraInfo"]["cameraType"] = cg.cam_ifo.cameraType;
    item["cameraInfo"]["cameraBrand"] = cg.cam_ifo.cameraBrand;
    item["cameraInfo"]["user"] = cg.cam_ifo.user;
    item["cameraInfo"]["passwd"] = cg.cam_ifo.passwd;
    item["cameraInfo"]["recRegion"] = rect_to_json_imp(cg.cam_ifo.rec_region);
    item["cameraInfo"]["delaySeconds"] = cg.cam_ifo.delay_seconds;

    item["NVRInfo"] = Json::Value(Json::objectValue);
    if (cg.nvr_ifo.ok) {
      item["NVRInfo"]["NVRIp"] = cg.nvr_ifo.NVRIp;
      item["NVRInfo"]["NVRChannel"] = cg.nvr_ifo.NVRChannel;
      item["NVRInfo"]["NVRBrand"] = cg.nvr_ifo.NVRBrand;
      item["NVRInfo"]["passwd"] = cg.nvr_ifo.passwd;
      item["NVRInfo"]["user"] = cg.nvr_ifo.user;
    }
    root["cameraGroups"].append(item);
  }

  if (write_file) {
    std::ofstream ofile;
    ofile.open(str);
    ofile << root.toStyledString();
    ofile << std::endl;
    ofile.close();
  } else {
    str = root.toStyledString();
  }
  return 0;
}

int string_to_struct(const std::string& str, ConfigInfo& cfg_ifo, bool read_file) {
  Json::Reader reader;
  Json::Value root;

  cfg_ifo.cameraGroups.clear();
  
  if (read_file) {
    std::ifstream ifs;
    ifs.open(str);
    if (!ifs.is_open()) { return file_not_found_error; }
    if (!reader.parse(ifs, root)) { return json_read_parse_error; }
  } else {
    if (!reader.parse(str, root)) { return json_read_parse_error; }
  }
  
  cfg_ifo.smartboxId = root.get("smartboxId", Json::Value(Json::stringValue)).asString();
  cfg_ifo.serialNumber = root.get("serialNumber", Json::Value(Json::stringValue)).asString();
  cfg_ifo.smartboxIp = root.get("smartboxIp", Json::Value(Json::stringValue)).asString();
  
  cfg_ifo.configVersion = root.get("configVersion", Json::Value(Json::stringValue)).asString();
  cfg_ifo.postAPI.uploadAlarmFast = root["postAPI"].get("uploadAlarmFast", Json::Value(Json::stringValue)).asString();
  cfg_ifo.postAPI.uploadAlarmSlow = root["postAPI"].get("uploadAlarmSlow", Json::Value(Json::stringValue)).asString();
  cfg_ifo.postAPI.checkDevice = root["postAPI"].get("checkDevice", Json::Value(Json::stringValue)).asString();
  cfg_ifo.postAPI.uploadHttpHeart = root["postAPI"].get("uploadHttpHeart", Json::Value(Json::stringValue)).asString();
  cfg_ifo.postAPI.queryDevice = root["postAPI"].get("queryDevice", Json::Value(Json::stringValue)).asString();
  cfg_ifo.postAPI.uploadCameraImg = root["postAPI"].get("uploadCameraImg", Json::Value(Json::stringValue)).asString();
  cfg_ifo.postAPI.uploadFile = root["postAPI"].get("uploadFile", Json::Value(Json::stringValue)).asString();
  cfg_ifo.postAPI.imageDetect = root["postAPI"].get("imageDetect", Json::Value(Json::stringValue)).asString();

  cfg_ifo.httpServer = root.get("httpServer", Json::Value(Json::stringValue)).asString();
  cfg_ifo.socketServer = root.get("socketServer", Json::Value(Json::stringValue)).asString();
  cfg_ifo.modelDir = root.get("modelDir", Json::Value(Json::stringValue)).asString();
  cfg_ifo.mediaDir = root.get("mediaDir", Json::Value(Json::stringValue)).asString();
  cfg_ifo.historyDir = root.get("historyDir", Json::Value(Json::stringValue)).asString();
  cfg_ifo.historyDay = root.get("historyDay", Json::Value(Json::intValue)).asInt();
  cfg_ifo.gps = root.get("gps", Json::Value(Json::stringValue)).asString();

  // mediaKitInfo
  if (root.isMember("mediaKitInfo") && root["mediaKitInfo"].isMember("mediaKitServer")) {
    cfg_ifo.mediaKitInfo.mediaKitServer = root["mediaKitInfo"].get("mediaKitServer", Json::Value(Json::stringValue)).asString();
    cfg_ifo.mediaKitInfo.mediaKitClient = root["mediaKitInfo"].get("mediaKitClient", Json::Value(Json::stringValue)).asString();
    auto mediaKitAPI = root["mediaKitInfo"].get("mediaKitAPI", Json::Value(Json::objectValue));
    cfg_ifo.mediaKitInfo.mediaKitAPI.addCamera = mediaKitAPI.get("addCamera", Json::Value(Json::stringValue)).asString();
    cfg_ifo.mediaKitInfo.mediaKitAPI.getVideo = mediaKitAPI.get("getVideo", Json::Value(Json::stringValue)).asString();
    cfg_ifo.mediaKitInfo.mediaKitAPI.cameraProxy = mediaKitAPI.get("cameraProxy", Json::Value(Json::stringValue)).asString();
    cfg_ifo.mediaKitInfo.mediaKitAPI.addDeleteStrategy = mediaKitAPI.get("addDeleteStrategy", Json::Value(Json::stringValue)).asString();
    auto deleteStrategy = root["mediaKitInfo"].get("deleteStrategy", Json::Value(Json::objectValue));
    cfg_ifo.mediaKitInfo.deleteStrategy.mainStreamDay = deleteStrategy.get("mainStreamDay", Json::Value(Json::intValue)).asInt();
    cfg_ifo.mediaKitInfo.deleteStrategy.mainStreamHour = deleteStrategy.get("mainStreamHour", Json::Value(Json::intValue)).asInt();
    cfg_ifo.mediaKitInfo.deleteStrategy.subStreamDay = deleteStrategy.get("subStreamDay", Json::Value(Json::intValue)).asInt();
    cfg_ifo.mediaKitInfo.deleteStrategy.subStreamHour = deleteStrategy.get("subStreamHour", Json::Value(Json::intValue)).asInt();
    cfg_ifo.mediaKitInfo.ok = true;
  }

  // tasks
  if (root.isMember("tasks")) {
    for (auto t : root["tasks"]) { cfg_ifo.tasks.push_back(t.asString()); }
  }

  if (!root.isMember("cameraGroups")) { return json_key_error;}
  for (auto group_js : root["cameraGroups"]) {
    algo::CameraGroup cam_group = parse_cameraGroup(group_js);
    cfg_ifo.cameraGroups.push_back(cam_group); 
  }
  
  return 0;
}

algo::CameraGroup parse_cameraGroup(Json::Value group_js) {
  algo::CameraGroup cam_group;

  cam_group.cam_ifo.cameraType = group_js["cameraInfo"]["cameraType"].asString();
  cam_group.cam_ifo.cameraBrand = group_js["cameraInfo"]["cameraBrand"].asString();
  cam_group.cam_ifo.cameraId = group_js["cameraInfo"]["cameraId"].asString();
  cam_group.cam_ifo.rtspAddress = group_js["cameraInfo"]["rtspAddress"].asString();
  cam_group.cam_ifo.cameraIp = group_js["cameraInfo"]["cameraIp"].asString();
  cam_group.cam_ifo.user = group_js["cameraInfo"]["user"].asString();
  cam_group.cam_ifo.passwd = group_js["cameraInfo"]["passwd"].asString();
  cam_group.cam_ifo.delay_seconds = group_js["cameraInfo"].get("delaySeconds", Json::Value(5)).asInt();
  if (group_js["cameraInfo"].isMember("recRegion")) {
    cam_group.cam_ifo.rec_region = json_to_rect_imp(group_js["cameraInfo"]["recRegion"]);
  }

  // NVRInfo
  if (group_js.isMember("NVRInfo") && group_js["NVRInfo"].isMember("NVRIp")) {
    cam_group.nvr_ifo.NVRIp = group_js["NVRInfo"]["NVRIp"].asString();
    cam_group.nvr_ifo.NVRChannel = group_js["NVRInfo"]["NVRChannel"].asString();
    cam_group.nvr_ifo.NVRBrand = group_js["NVRInfo"]["NVRBrand"].asString();
    cam_group.nvr_ifo.passwd = group_js["NVRInfo"]["passwd"].asString();
    cam_group.nvr_ifo.user = group_js["NVRInfo"]["user"].asString();
    cam_group.nvr_ifo.ok = true;
  }
  // cam_mdl
  
  return cam_group;
}

std::string get_machine_ip() {
#ifdef _WIN32
  return "";
#else
  std::string command = "ifconfig > ip.txt"; 
  system(command.c_str());

  std::ifstream in("ip.txt");
  std::string line, tmp,ret_ip;
  if (!in) {
    spdlog::get("logger")->info("no such file: ip.txt");
    return "";
  }
  while (getline(in, line)) {
    std::stringstream ss(line);
    ss >> tmp;
    if (tmp == std::string("inet")) {
      ss >> ret_ip;
      if (ret_ip.length() >= 7){
        std::vector<std::string> ips;
        boost::algorithm::split(ips, ret_ip, boost::is_any_of("."), boost::token_compress_on);
        if (ips.size() == 4 && ips.back() != "1") {
          break;
        }
      }
    }
  }
  in.close();
  return ret_ip;
  
#endif
}

void make_mask(std::string type, std::string sub_type, cv::Mat& img, cv::Mat& mask_img, std::vector<cv::Point> region) {
  if (region.size() == 0) { img.copyTo(mask_img);  return;}

  cv::Mat mask = cv::Mat::zeros(img.size(), CV_8UC1);
  cv::fillConvexPoly(mask, region, cv::Scalar(255));
  // 取反
  if (type == "VihicleDetection") { 
    cv::bitwise_not(mask, mask); 
    mask_img = cv::Mat::zeros(img.size(), img.type()) + cv::mean(img);
    cv::copyTo(img, mask_img, mask);
  }
  else if (type == "SandDetection" && sub_type == "SandDetection") {

    auto minmax_x = std::minmax_element(region.begin(), region.end(), [](cv::Point& a, cv::Point& b){ return a.x < b.x;});
    auto minmax_y = std::minmax_element(region.begin(), region.end(), [](cv::Point& a, cv::Point& b){ return a.y < b.y;});
    cv::Rect roi = cv::Rect(cv::Point(minmax_x.first->x, minmax_y.first->y), 
                            cv::Point(minmax_x.second->x, minmax_y.second->y));
    cv::Mat fg = cv::Mat::zeros(img.size(), CV_8UC3);
    cv::Mat mask = cv::Mat::zeros(img.size(), CV_8UC1);
    cv::fillConvexPoly(mask, region, cv::Scalar(255)); 
    cv::copyTo(img, fg, mask);
    mask_img = fg(roi).clone();
  }
  else {
    spdlog::get("logger")->info("make_mask: not support: {}", type);
    img.copyTo(mask_img);
  }
}


// void post_data_imp_v1(LogInfo *log_ifo, ConfigInfo* cfg_ifo, std::multimap<int64, algo::PostInfo>& cur_post_ifos) {
//   for (auto it = cur_post_ifos.begin(); it != cur_post_ifos.end();it++) {
//     if (it->second.algo_type == "uploadImg") { continue;}
//     if (it->second.alarm < 0) { continue; }
//     Json::Value root;
    
//     root["smartbox_name"] = cfg_ifo->smartboxName;
//     root["check_type"] = it->second.algo_type;
//     root["happen_time"] = time_int64_to_string(it->first, "%Y-%m-%d %H:%M:%S");

//     std::string uri = cfg_ifo->postAPI.uploadAlarmFast;
//     if (it->second.algo_type == "PeopleTrafficFlow") {
//       root["smartbox_id"] = cfg_ifo->smartboxId;
//       root["is_warning"] = 2;
//       Json::Value result_describe;
//       result_describe["video_time"] = time_int64_to_string(it->first, "%Y-%m-%d %H:%M:%S");
//       result_describe["total_car"] = it->second.car_flow.total_car;
//       result_describe["total_person"] = it->second.car_flow.total_person;
//       result_describe["small_car"] = it->second.car_flow.small_car;
//       result_describe["medium_car"] = it->second.car_flow.medium_car;
//       result_describe["large_car"] = it->second.car_flow.large_car;
//       root["result_describe"] = result_describe.toStyledString();
//     }
//     else {
//       root["smartbox_id"] = cfg_ifo->smartboxId + "0";
//       // 不用审核 
//       root["is_warning"] = 1;
//       root["result_describe"] = it->second.alarm_info;
//     }
//     // first log
//     if (log_ifo->log_core_text) spdlog::get("logger")->info("SmartBox::post_data_imp post_data: \n{}", root.toStyledString());

//     // second add img
//     if (it->second.algo_type != "PeopleTrafficFlow") { 
//       cv::Mat img = cv::imread(it->second.img_path);
//       std::string img_base64;
//       encode_image(img, img_base64);
//       root["warning_image"] = img_base64; 
//     }
//     else { root["warning_image"] = ""; }
//     std::string msg = root.toStyledString();

//     post_data_base(msg, cfg_ifo->httpServer, uri, -1, log_ifo);

//   }
// }

void post_data_text_v2(LogInfo *log_ifo, ConfigInfo* cfg_ifo, std::multimap<int64, algo::PostInfo>& cur_post_ifos) {
  for (auto it = cur_post_ifos.begin(); it != cur_post_ifos.end();it++) {
    if (it->second.alarm < 0) { continue; }
    Json::Value root;

    root["checkType"] = it->second.algo_type;
    root["happenTime"] = time_int64_to_string(it->second.start_time, "%Y-%m-%d %H:%M:%S");

    std::string uri = cfg_ifo->postAPI.uploadAlarmFast;
    if (it->second.algo_type == "PeopleTrafficFlow") {
      root["cameraId"] = it->second.cam_grp->cam_ifo.cameraId;
      root["smartboxId"] = cfg_ifo->smartboxId;
      root["eventId"] = it->second.eventId;
      root["isWarning"] = 2;
      Json::Value result_describe;
      result_describe["video_time"] = time_int64_to_string(it->second.start_time, "%Y-%m-%d %H:%M:%S");
      // result_describe["total_car"] = it->second.car_flow.total_car;
      // result_describe["total_person"] = it->second.car_flow.total_person;
      // result_describe["small_car"] = it->second.car_flow.small_car;
      // result_describe["medium_car"] = it->second.car_flow.medium_car;
      // result_describe["large_car"] = it->second.car_flow.large_car;
      root["resultDescribe"] = result_describe.toStyledString();
    }
    else if (it->second.algo_type == "uploadImg") {
      if (cfg_ifo->postAPI.uploadCameraImg == "") {continue;}
      root["cameraId"] = it->second.cam_grp->cam_ifo.cameraId;
      std::string name="";
      int ret = post_file(name, cfg_ifo->httpServer, cfg_ifo->postAPI.uploadFile, it->second.img_path, "name", 5, 1, log_ifo);
      root["imgName"] = name;
      uri = cfg_ifo->postAPI.uploadCameraImg;
    }
    else {
      root["cameraId"] = it->second.cam_grp->cam_ifo.cameraId;
      root["smartboxId"] = cfg_ifo->smartboxId;
      // root["startTime"] = time_int64_to_string(it->second.start_time, "%Y-%m-%d %H:%M:%S");
      // root["endTime"] = time_int64_to_string(it->second.end_time, "%Y-%m-%d %H:%M:%S");

      // 1.等待 2.正常 3.误报
      root["misreportState"] = 1; 
      if (it->second.algo_type == "SmogWarning") { root["misreportState"] = 2; }
      root["eventId"] = it->second.eventId;
      root["isWarning"] = 1;
      root["resultDescribe"] = it->second.alarm_info;
    }
    std::string ret_body, msg = root.toStyledString();
    if (log_ifo->log_level_1) spdlog::get("logger")->info("SmartBox::post_data_text_v2 post_data: \n{}", msg);

    post_data_base(ret_body, msg, cfg_ifo->httpServer, uri, -1, 1, log_ifo);

  }
}

int check_device(LogInfo *log_ifo, ConfigInfo* cfg_ifo, std::string local_ip, std::string serial_number, std::string secret_key) {
  std::vector<std::string> camera_ips;
  // find_camera_ip(local_ip, camera_ips);
  std::vector<std::string> ips;
	boost::algorithm::split(ips, local_ip, boost::is_any_of("."), boost::token_compress_on);
  if (ips.size() != 4) {
    spdlog::get("logger")->info("find_camera_ip error local_ip: {}", local_ip);
    return -1;
  }

  for (int i = 200; i < 205; i++) {
    std::string new_ip = ips[0] + "." + ips[1] + "." + ips[2] + "." + std::to_string(i);
    spdlog::get("logger")->info("find_camera_ip new_ip: {}", new_ip);
    if (local_ip == new_ip) { continue; }

    if (monitor_device_online(new_ip) >= 0) { camera_ips.push_back(new_ip); }
  }


  Json::Value root;
  root["serialNumber"] = serial_number;
  root["smartboxIp"] = cfg_ifo->smartboxIp;
  root["secretKey"] = secret_key;
  root["cameras"] = Json::Value(Json::arrayValue);
  for (auto ip : camera_ips) { 
    Json::Value cam;
    cam["cameraIp"] = ip;
    root["cameras"].append(cam);
  }
  std::string ret_body, msg = root.toStyledString();
  std::string uri = cfg_ifo->postAPI.checkDevice;
  int ret = post_data_base(ret_body, msg, cfg_ifo->httpServer, uri, -1, 1, log_ifo);
  if (ret != 0) { return ret;}

  if (log_ifo->log_level_1) spdlog::get("logger")->info("SmartBox::check_device msg: {}", msg);
  if (log_ifo->log_level_1) spdlog::get("logger")->info("SmartBox::check_device res->body: \n{}\n", ret_body);
  return 0;
}

int query_device(LogInfo *log_ifo, ConfigInfo* cfg_ifo, ActivateCode* act_code, std::string secret_key) {
  Json::Value root;
  root["serialNumber"] = cfg_ifo->serialNumber;
  root["smartboxIp"] = cfg_ifo->smartboxIp;
  
  std::string ret_body, msg = root.toStyledString();
  spdlog::get("logger")->info("SmartBox::query_device post_data_base msg: {}", msg);
  std::string uri = cfg_ifo->postAPI.queryDevice;
  int ret = post_data_base(ret_body, msg, cfg_ifo->httpServer, uri, -1, 1, log_ifo);
  if (ret != 0) { 
    spdlog::get("logger")->info("SmartBox::query_device post_data_base ret: {}", ret);
    return ret;
  }

  Json::Value ret_json;
  ret = parse_json(ret_body, ret_json, false);
  // 解析 密钥不匹配时直接退出程序
  std::string new_key = ret_json["secretKey"].asString();
  ret = act_code->check_expiration(check_cpu_adress, new_key);
  if (ret != 0) {
    spdlog::get("logger")->info("SmartBox::query_device check_expiration ret: {}", ret);
    return ret;
  }
  // 更新到文件 比较前后数据
  cfg_ifo->smartboxId = ret_json["smartboxId"].asString();
  std::vector<algo::CameraGroup> ori_cam_group = cfg_ifo->cameraGroups;
  cfg_ifo->cameraGroups.clear();
  for (auto item : ret_json["cameraGroups"]) {
    algo::CameraGroup cg = parse_cameraGroup(item);
    cfg_ifo->cameraGroups.push_back(cg);
  }
  std::string cfg_path = CFG_PATH;
  struct_to_string(*cfg_ifo, cfg_path, true);

  // // 侦测到相机数量变化时，立即重启程序
  // if (/*ori_size > 0 && */ori_size != cfg_ifo->cameraGroups.size()) { 
  //   spdlog::get("logger")->info("SmartBox::query_device reboot, ori: {}, now: {}", ori_size, cfg_ifo->cameraGroups.size());
  //   system("reboot"); 
  // }

  if (log_ifo && log_ifo->log_level_4) spdlog::get("logger")->info("SmartBox::query_device ori_cam_group.size():{}, cfg_ifo->cameraGroups.size():{}", ori_cam_group.size(), cfg_ifo->cameraGroups.size());
  int same_flag = 0;
  if (ori_cam_group.size() != cfg_ifo->cameraGroups.size()) { same_flag = -1; }
  else {
    for (int i = 0; i < ori_cam_group.size(); i++) {
      if (!(ori_cam_group[i] == cfg_ifo->cameraGroups[i])) { same_flag = -1; }
    }
  }
  if (log_ifo && log_ifo->log_level_4) spdlog::get("logger")->info("SmartBox::query_device same_flag:{}", same_flag);
  return same_flag;
}

int check_register(LogInfo *log_ifo, ConfigInfo* cfg_ifo, ActivateCode* act_code) {
  int ret = 0;
  std::string local_ip;
  int ip_cnt = 0;
  while (ip_cnt++ < 5) {
    local_ip = get_machine_ip();
    // local_ip = get_linux_ip();
    if (log_ifo->log_level_1) spdlog::get("logger")->info("SmartBox::check_register get_machine_ip {}", local_ip);
    if (!local_ip.empty()) { break;}
    std::this_thread::sleep_for(milliseconds(5000));
  }
  std::string serial_number = act_code->get_cpu_adress();
  std::string secret_key = act_code->gen_code(serial_number, 99);
  cfg_ifo->smartboxIp = local_ip;
  cfg_ifo->serialNumber = serial_number;
  if (log_ifo->log_level_1) spdlog::get("logger")->info("SmartBox::check_register local_ip {}, serial_number: {}, size:{}, length:{}", local_ip, serial_number, serial_number.size(), serial_number.length());

  int64 check_time=0,query_time=0, cur_time=0;
  int query_cnt = 0;
  while (true) {
    std::this_thread::sleep_for(milliseconds(5000));
    cur_time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
    // if (query_cnt > 10) { 
    //   spdlog::get("logger")->info("SmartBox::query_device reboot, query_cnt: {}", query_cnt);
    //   system("reboot");  
    // }
    
    // 先查询审批结果
    if (cur_time - query_time > 1 * 60 * 1e3) {
      query_time = cur_time;
      ret = query_device(log_ifo, cfg_ifo, act_code, secret_key);
      spdlog::get("logger")->info("SmartBox::check_register query_device ret: {}", ret);
      // 已审批状态 直接退出
      if (ret == 0) { break; }
      query_cnt++;
    }
    
    // 未上传 || 已上传未审批
    // 上传审批信息
    if (cur_time - check_time > 3 * 60 * 1e3) {
      check_time = cur_time;
      ret = check_device(log_ifo, cfg_ifo, local_ip, serial_number, secret_key);
      if (ret != 0) { continue; }
    }

  }
  return 0;
}


int find_camera_ip(std::string local_ip, std::vector<std::string>& camera_ips) {
  std::vector<std::string> ips;
	boost::algorithm::split(ips, local_ip, boost::is_any_of("."), boost::token_compress_on);
  if (ips.size() != 4) {
    spdlog::get("logger")->info("find_camera_ip error local_ip: {}", local_ip);
    return -1;
  }
  Headers header = {
    {"Accept", "text/html, application/xhtml+xml, */*"},
    {"Accept-Language", "zh-CN"},
    {"User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"},
    {"Accept-Encoding", "gzip, deflate"},
    {"Host", "192.168.10.158"},
    {"Connection", "Keep-Alive"}
  };
  for (int i = 200; i < 205; i++) {
    std::string new_ip = ips[0] + "." + ips[1] + "." + ips[2] + "." + std::to_string(i);
    spdlog::get("logger")->info("find_camera_ip new_ip: {}", new_ip);
    if (local_ip == new_ip) { continue; }

    Client cli(new_ip.c_str());
    cli.set_connection_timeout(1,0);
    cli.set_read_timeout(1,0);
    cli.set_write_timeout(1,0);

    std::string uri = "/ISAPI/System/time/localTime";
    auto res = cli.Get(uri.c_str(), header); 
    if (res && res->status == 200) { 
      camera_ips.push_back(new_ip);
      spdlog::get("logger")->info("find_camera_ip ok: {}", new_ip);
    }
  }
  return 0;
}

void send_local_heart(LogInfo *log_ifo, ConfigInfo* cfg_ifo) {
  int ret = 0;
  std::string uri = cfg_ifo->postAPI.uploadHttpHeart;
  if (uri.empty()) { return; }

  Json::Value root;
  root["smartboxId"] = cfg_ifo->smartboxId;
  root["curVersion"] = CUR_VERSION;
  DiskInfo du;
  ret = get_disk_percent(du);
  root["diskInfo"] = util::Format("{0}/{1}", du.used, du.total);
#ifdef __arm__
	root["boardThermal"] = get_board_thermal(check_orangepi);
#else 
	root["boardThermal"] = get_board_thermal(check_x86_linux);
#endif
  
  for (auto& cg : cfg_ifo->cameraGroups) {
    Json::Value ci;
    ci["cameraId"] = cg.cam_ifo.cameraId;
    ci["cameraStatus"] = int(cg.cam_ifo.cameraStatus);
    root["cameraInfos"].append(ci);
  }
  std::string ret_body, msg = root.toStyledString();
  if (log_ifo->log_level_1) spdlog::get("logger")->info("send_http_heart: \n{}", msg);

  post_data_base(ret_body, msg, cfg_ifo->httpServer, uri, -1, 1, log_ifo);
  return ;
}

}